package org.ms.mconf.sdk.service.support;

import lombok.extern.slf4j.Slf4j;
import org.micro.URL;
import org.ms.mconf.sdk.model.*;
import org.ms.mconf.sdk.Constants;
import org.ms.mconf.sdk.exception.MicroConfigException;
import org.ms.mconf.sdk.service.IOpsService;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * The Abstract Config Service
 *
 * @author lry
 */
@Slf4j
public abstract class AbstractService implements IOpsService {

    protected String group;
    protected String node;
    protected String env;
    protected String application;
    protected String version;

    protected ThreadPoolExecutor subscribeThreadPoolExecutor;
    protected Map<String, Set<MetaDataConfig>> subscribeMetaDataConfigs = new ConcurrentHashMap<>();
    protected Map<String, Set<MetaMultiDataConfig>> subscribeMetaMultiDataConfigs = new ConcurrentHashMap<>();
    private AtomicInteger subscribeCounter = new AtomicInteger(0);


    @Override
    public void initialize(URL url) throws MicroConfigException {
        this.group = Constants.get(url, Constants.GROUP);
        this.node = url.getPath();
        if (node == null || node.length() == 0) {
            this.node = Constants.NODE.getValue();
        }
        this.env = url.getParameter(Constants.ENV_KEY);
        this.application = url.getParameter(Constants.APPLICATION_KEY);
        this.version = url.getParameter(Constants.VERSION_KEY);

        // initialize config subscribe executor thread pool
        int corePoolSize = Constants.getIntValue(url, Constants.SUB_EXECUTOR_CORE_POOL_SIZE);
        int maximumPoolSize = Constants.getIntValue(url, Constants.SUB_EXECUTOR_MAXIMUM_POOL_SIZE);
        long keepAliveTime = Constants.getIntValue(url, Constants.SUB_EXECUTOR_KEEP_ALIVE_TIME);
        this.subscribeThreadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), r -> {
            Thread t = new Thread(r);
            t.setName("config-subscribe-executor-" + subscribeCounter.getAndIncrement());
            t.setDaemon(true);
            return t;
        });


    }

    @Override
    public boolean publish(MetaMultiDataConfig metaMultiDataConfig) throws MicroConfigException {
        MetaConfig meta = metaMultiDataConfig.getMeta();
        MetaConfig.checkNotBlank(meta);

        List<DataConfig> dataConfigs = metaMultiDataConfig.getData();
        if (dataConfigs == null || dataConfigs.isEmpty()) {
            throw new NullPointerException();
        }

        for (DataConfig dataConfig : dataConfigs) {
            DataConfig.checkNotBlank(dataConfig);
        }

        return true;
    }

    @Override
    public void destroy() throws MicroConfigException {
        if (subscribeThreadPoolExecutor != null && !subscribeThreadPoolExecutor.isShutdown()) {
            subscribeThreadPoolExecutor.shutdown();
        }
    }

}
